import { FlyItem } from './game/FlyItem';
import { _decorator, Component, Node, Material, SpriteAtlas, SpriteFrame, Sprite, color, Vec3, EditBox } from 'cc';
import { ReactiveProperty } from '../../scripts/libs/rxjs/cc3/ReactiveProperty';
import { ResType, rm } from '../../scripts/managers/ResourceManager';
import { Observable, of, subscribeOn } from 'rxjs';
import { TweenToStart } from '../../scripts/libs/rxjs/cc3/TweenStart';
import { TransparentPass } from '../../scripts/libs/rxjs/cc3/CommonObservable';
import { instantiate } from 'cc';
import { lm } from './LobbyManager';
import { StageInfo } from './game/basic';
import { SmartNodePool } from '../../scripts/libs/utils/SmartNodePool';
import { CaidaiHelper } from './CaidaiHelper';
import { DevConfig } from '../../scripts/managers/DevConfig';
import { generateMapping, stageNumMapTo } from '../../scripts/libs/utils/RandomChooseTools';
import { log } from 'cc';
const { ccclass, property } = _decorator;

export class ResourceHelper {

    // Prefab
    static PrefabPath_DebugLabel = 'ab_lobby/Prefabs/RoomPanel/prefabs/DebugLabel';

    static GetDebugLabel() {
        let node = instantiate(rm.prefabs[this.PrefabPath_DebugLabel]);
        return node;
    }

    // Material
    static CommonMaterialReady = ReactiveProperty.Create(false);

    static HighlightSingleMaterialPath = 'ab_lobby/Materials/builtin-sprite-highlight-single';
    static get HighlightSingleMaterial(): Material {
        return rm.materials[this.HighlightSingleMaterialPath];
    }

    static CreateHighlightSingleFlush(node: Node) {
        let sprite = node.getComponent(Sprite);
        if (sprite == null) return of(null);
        return new Observable(observer => {
            sprite.customMaterial = this.HighlightSingleMaterial;
            let com = node.getComponent('effect_highlight_light_single');
            if (com == null) com = node.addComponent('effect_highlight_light_single');
            // com.useMaterialInstance = true;
            com['diff'] = -1;
            // com.rot = -.1;
            // com.transition = -.05;
            // com.width = .15;
            // com.color = color().fromHEX('FFFFFF80');
            let _sub = TweenToStart(com, .4, { diff: 1 }, { easing: 'sineOutIn' }).subscribe(TransparentPass(observer));
            return () => {
                if (_sub) _sub.unsubscribe();
                sprite.customMaterial = null;
                com?.destroy();
            }
        });
    }

    static GetStageJsonPath(stageId: number) {
        return `ab_lobby/Json/stage${stageId.toString().padStart(3, '0')}`;
    }

    static LoadStageAssets(stageId: number): Observable<StageInfo> {
        return new Observable(observer => {
            let rawStageId = stageId; // rawStageId用于控制关卡号在STAGE_NUM_MAX之内
            if (DevConfig.STAGE_RANDOM_REPEAT) {
                if (rawStageId > DevConfig.STAGE_NUM_MAX) {
                    // TODO: 映射到之前的关卡
                    // let stageIdz = (rawStageId - 1) % DevConfig.STAGE_NUM_MAX;
                    // let seed = Math.floor(rawStageId / DevConfig.STAGE_NUM_MAX).toString();
                    // let mapping = generateMapping(DevConfig.STAGE_NUM_MAX, seed + 1);
                    // rawStageId = mapping[stageIdz] + 1;
                    // log("stageNum over, repeat:", stageId, rawStageId);
                    rawStageId = stageNumMapTo(stageId).result;
                    log("stageNum over, repeat:", stageId, rawStageId);
                }
            }
            let path = this.GetStageJsonPath(rawStageId);
            if (rm.jsonAssets[path] != null) {
                observer.nextAndComplete(rm.jsonAssets[path].json as StageInfo);
            } else {
                rm.loadRes([
                    [path, ResType.JsonAsset]
                ]).subscribe({
                    next: _ => {
                        if (_.status != 0) {
                            lm.frontTipShow(`Load stage failed! (stage:${stageId}) rawStageId:${rawStageId}`);
                            observer.nextAndComplete(null);
                        }
                    },
                    complete: () => {
                        if (rm.jsonAssets[path] != null) {
                            let stageInfo = rm.jsonAssets[path].json as StageInfo;
                            if (stageInfo.stageId != null && stageInfo.stageId != stageId) {
                                console.warn('StageId in json is not match with stageId in file name.');
                                // return;
                            }
                            stageInfo.stageId = stageId;
                            observer.nextAndComplete(stageInfo);
                        }
                    }
                });
            }
        });
    }


    static Atlas_Tptex2_Path = 'ab_lobby/texture-2/tptex2';
    static GetTpTex2Atlas() {
        return rm.spriteAtlas[this.Atlas_Tptex2_Path];
    }

    static PrefabPath_Ground = 'ab_lobby/Prefabs/GamePanel/game/Ground';
    static PrefabPath_ChangeSmoke = 'ab_lobby/Particle/Smoke0/ChangeSmoke/ChangeSmoke';
    static PrefabPath_FlyItem = 'ab_lobby/Prefabs/Common/FlyItem';
    static PrefabPath_FlyCoin = 'ab_lobby/Prefabs/Common/FlyCoin';
    static PrefabPath_TutorialHand = 'ab_lobby/spine/TutorialHand/TutorialHand';
    static PrefabPath_TutorialTip = 'ab_lobby/Prefabs/GamePanel/game/TutorialTip';
    static PrefabPath_BlinkPlateDestroy = 'ab_lobby/Particle/Blink0/BlinkPlateDestroy';
    static PrefabPath_BurstView = 'ab_lobby/Particle/Burst0/Burst0';

    static GroundPool = new SmartNodePool();
    static ChangeSmokePool = new SmartNodePool();
    static SwimringPool = new SmartNodePool();
    static FlyItemPool = new SmartNodePool();
    static FlyCoinPool = new SmartNodePool();
    static TutorialHandPool = new SmartNodePool();
    static TutorialTipPool = new SmartNodePool();
    static BlinkPlateDestroyPool = new SmartNodePool();
    static Burst0Pool = new SmartNodePool();
    static PreparePool() {
        this.GroundPool.setPrefab(rm.prefabs[this.PrefabPath_Ground]);
        this.GroundPool.prepare(25);
        this.ChangeSmokePool.setPrefab(rm.prefabs[this.PrefabPath_ChangeSmoke]);
        this.ChangeSmokePool.prepare(2);
        this.FlyItemPool.setPrefab(rm.prefabs[this.PrefabPath_FlyItem]);
        this.FlyItemPool.prepare(10);
        this.FlyCoinPool.setPrefab(rm.prefabs[this.PrefabPath_FlyCoin]);
        this.FlyCoinPool.prepare(100);
        this.TutorialHandPool.setPrefab(rm.prefabs[this.PrefabPath_TutorialHand]);
        this.TutorialHandPool.prepare(1);
        this.TutorialTipPool.setPrefab(rm.prefabs[this.PrefabPath_TutorialTip]);
        this.TutorialTipPool.prepare(1);
        this.BlinkPlateDestroyPool.setPrefab(rm.prefabs[this.PrefabPath_BlinkPlateDestroy]);
        this.BlinkPlateDestroyPool.prepare(6);
        this.Burst0Pool.setPrefab(rm.prefabs[this.PrefabPath_BurstView]);
        this.Burst0Pool.prepare(6);
        CaidaiHelper.PrepareCaidai(30);
    }

    static ResList = [
        [this.Atlas_Tptex2_Path, ResType.SpriteAtlas, 0],
        [this.PrefabPath_Ground, ResType.Prefab, 0],
        [CaidaiHelper.PrefabPath_Caidai_0, ResType.Prefab, 0],
        [CaidaiHelper.PrefabPath_Caidai_1, ResType.Prefab, 0],
        [CaidaiHelper.PrefabPath_Caidai_2, ResType.Prefab, 0],
        [this.PrefabPath_ChangeSmoke, ResType.Prefab, 0],
        [this.PrefabPath_FlyItem, ResType.Prefab, 0],
        [this.PrefabPath_FlyCoin, ResType.Prefab, 0],
        [this.PrefabPath_TutorialHand, ResType.Prefab, 0],
        [this.PrefabPath_TutorialTip, ResType.Prefab, 0],
        [this.PrefabPath_BlinkPlateDestroy, ResType.Prefab, 0],
        [this.PrefabPath_BurstView, ResType.Prefab, 0],
    ];

    static EditResList = [
        [this.PrefabPath_DebugLabel, ResType.Prefab],
    ];

}

globalThis.ResourceHelper = ResourceHelper;